#include "ThreadObj.h"
#include <sys/prctl.h>
#include <iostream>

#if 1
#define CREATE_THREAD_ON_CONSTRUCT
#endif


ThreadObj::ThreadObj(const std::string &thName) : m_thName(thName)
{
    ResetCondsVariable();

#ifdef CREATE_THREAD_ON_CONSTRUCT
    CreateThread(); 
#endif

}

ThreadObj::~ThreadObj()
{
    DestroyThread();
}

bool ThreadObj::CreateThread()
{
    if (!IsThreadCreated()) {
        m_condNotifyCreate.ResetForVariable();
        std::cout << "in ThreadObj::CreateThread()  start CreateThread" << std::endl;
        m_thread = std::move(std::thread(&ThreadObj::ThreadFunc, this));
        auto isCreated = m_condNotifyCreate.WaitForVariable(500);
        if (!isCreated) {
            std::cerr << "in ThreadObj::CreateThread(), create thread error" << std::endl;
            return false;
        }
        SetIsThreadCreated(true);
        SetDoTaskStatus(DoTaskStatus::DOTASK_IDEL);
        std::cout << "in ThreadObj::CreateThread()  start thread obj done" << std::endl;
    }
    return true;
}

int ThreadObj::StartTask()
{
    if (!IsThreadCreated()) {
        printf("in ThreadObj::StartTask(), need to create thread\n");
        if (CreateThread() == false) {
            printf("in ThreadObj::StartTask(), create thread error\n");
            return -1;
        }
    } else {
        if (IsRunning()) {  
            printf("in ThreadObj::StartTask(), had task is running\n");
            return -1;
        }
    }

    m_condDoTask.NotifyOne();
    bool waitStatus = m_condNotifyStart.WaitForVariable(500);
    if (waitStatus) {
        return 0;
    } else {
        return -1;
    }
}


void ThreadObj::DestroyThread() 
{
    PreClearForStopThread();    // 停止任务之前，先清理现场

    m_stop = true;
    m_condDoTask.NotifyAll();
    if (m_thread.joinable()) {
        m_thread.join();
    }

    ResetThreadState();
}

/**
 * @brief 阻塞等待线程结束
 * 
 * @param status 
 * @param ms 
 * @return true 
 * @return false 
 */
bool ThreadObj::WaitTaskFinished(DoTaskStatus& status, int ms)
{
    if (IsRunning()) {
        if (ms == WAIT_FOR_INFINED) {
            m_condNotifyEnd.Wait();
        } else {
            auto ret = m_condNotifyEnd.WaitForTimeMS(ms);
            if (!ret) {
                return false;
            }
        }
    }
    status = GetDoTaskStatus();     // 无限等待
    return true;
}


void ThreadObj::ThreadFunc()
{
    // 设置线程名字
    prctl(PR_SET_NAME, (char*)m_thName.c_str());
    
    int ret = 0;
    while (!m_stop) {
        printf("ThreadObj::ThreadFunc(). in wait for task...\n");

        if (IsThreadCreated() == false) {       // 只需要通知一次
            m_condNotifyCreate.NotifyForVariable();
        }

        m_condNotifyStart.ResetForVariable();
        m_condDoTask.Wait();
        if (m_stop) {
            break;
        }

        SetDoTaskStatus(DoTaskStatus::DOTASK_RUNNING);
        m_condNotifyStart.NotifyForVariable();

        // 执行任务三部曲 PreDoTask,DoTask,PosDoTask
        ret = PreDoTask();
        if (ret == 0) {
            ret = DoTask();
            PosDoTask();
        }

        if (ret == 0) {
            SetDoTaskStatus(DoTaskStatus::DOTASK_SUCCESS);
        } else {
            SetDoTaskStatus(DoTaskStatus::DOTASK_FAILURE);
        }

        m_condNotifyEnd.NotifyAll();
        DoAfterTaskFinished();         // 接口函数，为子类提供任务完成后的回调接口。
    }

    ResetThreadState();
    printf("TreadObj  threadFunc()  exit\n");
}

void ThreadObj::SetDoTaskStatus(DoTaskStatus newStatus)
{
    if (m_doTaskStatus != newStatus) {
        auto preStatus = m_doTaskStatus;
        m_doTaskStatus = newStatus;
        StatusChangedHandle(preStatus, m_doTaskStatus);
    }
} 

DoTaskStatus ThreadObj::GetDoTaskStatus()
{
    return m_doTaskStatus;
}

bool ThreadObj::IsThreadCreated()
{
    return m_isThreadCreated.load();
}

void ThreadObj::SetIsThreadCreated(bool isThreadCreated)
{
    m_isThreadCreated.store(isThreadCreated);
}

bool ThreadObj::IsRunning()
{
    if (m_doTaskStatus == DoTaskStatus::DOTASK_RUNNING) {
        return true;
    }
    return false;
}

bool ThreadObj::CanHandleNewTask()
{
    if (IsThreadCreated() && IsRunning() == false) {
        return true;
    }
    return false;
}

void ThreadObj::ResetCondsVariable()
{
    m_condNotifyCreate.ResetForVariable();
    m_condNotifyStart.ResetForVariable();
    m_condNotifyEnd.ResetForVariable();
}

void ThreadObj::ResetThreadState()
{
    SetIsThreadCreated(false);
    SetDoTaskStatus(DoTaskStatus::DOTASK_IDEL);
    m_condNotifyCreate.NotifyForVariable();
    m_condNotifyStart.NotifyForVariable();
    m_condNotifyEnd.NotifyAll();
}   

void ThreadObj::SleepS(int second)
{
    std::this_thread::sleep_for(std::chrono::seconds(second));
}

void ThreadObj::SleepMS(int ms)
{
    std::this_thread::sleep_for(std::chrono::milliseconds(ms));
}

void ThreadObj::SleepUS(int us)
{
    std::this_thread::sleep_for(std::chrono::microseconds(us));
}
